package com.turbo.cloud.ums.web.logic;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.turbo.cloud.core.exception.BusinessException;
import com.turbo.cloud.core.utils.BeanListUtils;
import com.turbo.cloud.ums.constants.UMSConstants;
import com.turbo.cloud.starter.utils.RedisUtil;
import com.turbo.cloud.ums.utils.MenuTreeUtil;
import com.turbo.cloud.ums.web.entity.*;
import com.turbo.cloud.ums.web.model.api.UmsApiQo;
import com.turbo.cloud.ums.web.model.api.UmsApiDo;
import com.turbo.cloud.ums.web.model.api.UmsApiVo;
import com.turbo.cloud.ums.web.service.IUmsApiService;
import com.turbo.cloud.ums.web.service.IUmsMenuService;
import com.turbo.cloud.ums.web.service.IUmsPermissionApiRelationService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

/**
 * <p>
 * 菜单接口表 逻辑处理类
 * </p>
 *
 * @author zhangluning
 * @since 2022-08-13
 */
@Slf4j
@RequiredArgsConstructor
@Component
public class ApiLogic {

    final IUmsApiService umsApiService;
    final IUmsPermissionApiRelationService umsPermissionApiRelationService;
    final IUmsMenuService umsMenuService;
    final RedisUtil redisUtil;

    /**
     * 根据菜单ID，查询接口列表
     *
     * @param umsApiQo 接口实体
     * @return 分页数据
     */
    public List<UmsApiVo> queryApiListByMenuId(UmsApiQo umsApiQo) {
        // 如果是菜单组，需要把子菜单Id也拿出来
        List<UmsMenu> menuList = umsMenuService.list();
        List<String> menuIds = new ArrayList<>();
        if(!CollectionUtils.isEmpty(menuList)) {
            MenuTreeUtil.getChildrenMenuIds(umsApiQo.getMenuId(), menuList, menuIds);
        }

        LambdaQueryWrapper<UmsApi> apiLambdaQueryWrapper = new LambdaQueryWrapper<>();
        apiLambdaQueryWrapper
                .and(StrUtil.isNotEmpty(umsApiQo.getApiTitleByLike()), i -> i.like(UmsApi::getApiTitle, umsApiQo.getApiTitleByLike())
                .or()
                .like(StrUtil.isNotEmpty(umsApiQo.getApiUrlByLike()), UmsApi::getApiUrl, umsApiQo.getApiUrlByLike()));

        if(!CollectionUtils.isEmpty(menuIds)) {
            apiLambdaQueryWrapper.in(UmsApi::getMenuId, menuIds);
        } else {
            apiLambdaQueryWrapper.eq(UmsApi::getMenuId, umsApiQo.getMenuId());
        }
        apiLambdaQueryWrapper.orderByAsc(UmsApi::getSort);

        List<UmsApi> umsApiList = umsApiService.list(apiLambdaQueryWrapper);

        List<UmsApiVo> umsApiVoList = new ArrayList<>();
        BeanListUtils.copyList(umsApiList, umsApiVoList, UmsApiVo::new);

        return umsApiVoList;
    }

    /**
     * 根据菜单ID为Null，查询接口列表
     *
     * @param umsApiQo 接口实体
     * @return 分页数据
     */
    public List<UmsApiVo> queryApiListByNoMenuId(UmsApiQo umsApiQo) {
        // 如果是菜单组，需要把子菜单Id也拿出来
        List<UmsMenu> menuList = umsMenuService.list();


        LambdaQueryWrapper<UmsApi> apiLambdaQueryWrapper = new LambdaQueryWrapper<>();
        apiLambdaQueryWrapper
                .and(StrUtil.isNotEmpty(umsApiQo.getApiTitleByLike()), i -> i.like(UmsApi::getApiTitle, umsApiQo.getApiTitleByLike())
                        .or()
                        .like(StrUtil.isNotEmpty(umsApiQo.getApiUrlByLike()), UmsApi::getApiUrl, umsApiQo.getApiUrlByLike()));
        apiLambdaQueryWrapper.isNull(UmsApi::getMenuId);
        apiLambdaQueryWrapper.orderByDesc(UmsApi::getCreatedDate);

        List<UmsApi> umsApiList = umsApiService.list(apiLambdaQueryWrapper);

        List<UmsApiVo> umsApiVoList = new ArrayList<>();
        BeanListUtils.copyList(umsApiList, umsApiVoList, UmsApiVo::new);

        return umsApiVoList;
    }

    /**
     * 根据菜单ID，查询接口列表，并根据权限ID标记选中
     *
     * @param umsApiQo 接口实体
     * @return 分页数据
     */
    public List<UmsApiVo> queryApiCheckedListByMenuIdOfPermissionId(UmsApiQo umsApiQo) {
        List<UmsApiVo> apiVoList = queryApiListByMenuId(umsApiQo);

        /*
         * 根据权限ID获取权限关联的接口ID集合
         */
        LambdaQueryWrapper<UmsPermissionApiRelation> roleApiLambdaQueryWrapper = new LambdaQueryWrapper<>();
        roleApiLambdaQueryWrapper.eq(UmsPermissionApiRelation::getPermissionId, umsApiQo.getPermissionId());
        List<UmsPermissionApiRelation> permissionApiList = umsPermissionApiRelationService.list(roleApiLambdaQueryWrapper);

        if (!CollectionUtils.isEmpty(apiVoList) && !CollectionUtils.isEmpty(permissionApiList)) {
            List<String> apiIdList = permissionApiList.stream().map(UmsPermissionApiRelation::getApiId).toList();
            for (UmsApiVo umsApiVo : apiVoList) {
                umsApiVo.setChecked(apiIdList.contains(umsApiVo.getId()));
            }
        }

        return apiVoList;
    }

    /**
     * 新增接口
     *
     * @param umsApiDo 实体
     * @return
     */
    public Boolean createApi(UmsApiDo umsApiDo) {
        UmsApi umsApi = new UmsApi();
        BeanUtils.copyProperties(umsApiDo, umsApi);

        boolean result = umsApiService.save(umsApi);
        if (!result) {
            throw new BusinessException("新增接口失败");
        }
        return true;
    }

    /**
     * 修改接口
     *
     * @param umsApiDo 实体
     * @return
     */
    public Boolean modifyApi(UmsApiDo umsApiDo) {

        UmsApi umsApi = new UmsApi();
        BeanUtils.copyProperties(umsApiDo, umsApi);

        UmsApi umsApiTmp = umsApiService.getById(umsApiDo.getId());
        if (Objects.nonNull(umsApiTmp)) {
            if (StrUtil.isNotBlank(umsApiTmp.getApiUrl())) {
                // 修改接口信息中有接口地址变更，需要更新Redis缓存
                if (!umsApiTmp.getApiUrl().equals(umsApi.getApiUrl())) {
                    redisUtil.delete(UMSConstants.REDIS_KEY_API_PERMISSION_PREFIX + umsApiTmp.getApiUrl());
                    refreshRedisApiRoleId(umsApi);
                }
            }
        }

        boolean result = umsApiService.updateById(umsApi);
        if (!result) {
            throw new BusinessException("修改接口失败");
        }
        return true;
    }

    /**
     * 开启、关闭接口有效状态
     *
     * @param id 权限ID
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean enabledApiStateById(String id) {
        UmsApi umsApi = umsApiService.getById(id);
        if (Objects.isNull(umsApi)) {
            throw new BusinessException("接口不存在");
        }

        if (UMSConstants.DICT_STATE_ID_YES.equals(umsApi.getStateId())) {
            umsApi.setStateId(0);
        } else {
            umsApi.setStateId(1);
        }

        boolean result = umsApiService.updateById(umsApi);
        if (!result) {
            throw new BusinessException("修改接口状态失败");
        }
        return true;
    }

    /**
     * 删除接口
     *
     * @param id 接口ID
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean removeApiById(String id) {
        if (StrUtil.isBlank(id)) {
            throw new BusinessException("接口ID不能为空");
        }

        UmsApi umsApi = umsApiService.getById(id);
        if (Objects.nonNull(umsApi)) {
            // 删除Redis缓存
            LambdaQueryWrapper<UmsPermissionApiRelation> roleApiRelationLambdaQueryWrapper = new LambdaQueryWrapper<>();
            roleApiRelationLambdaQueryWrapper.eq(UmsPermissionApiRelation::getApiId, id);
            umsPermissionApiRelationService.remove(roleApiRelationLambdaQueryWrapper);
            redisUtil.delete(UMSConstants.REDIS_KEY_API_PERMISSION_PREFIX + umsApi.getApiUrl());

            boolean result = umsApiService.removeById(id);
            if (!result) {
                throw new BusinessException("删除接口失败");
            }
        }
        return true;
    }

    /**
     * 刷新Redis缓存
     *
     * @param umsApi Api
     */
    private void refreshRedisApiRoleId(UmsApi umsApi) {
        /*
         * 权限ID关联的接口ID
         */
        LambdaQueryWrapper<UmsPermissionApiRelation> permissionApiRelationLQWByApiId = new LambdaQueryWrapper<>();
        permissionApiRelationLQWByApiId.eq(UmsPermissionApiRelation::getApiId, umsApi.getId());
        List<UmsPermissionApiRelation> roleApiRelationList = umsPermissionApiRelationService.list(permissionApiRelationLQWByApiId);

        if (!CollectionUtils.isEmpty(roleApiRelationList)) {
            List<String> roleIds = roleApiRelationList.stream().map(UmsPermissionApiRelation::getPermissionId).toList();
            redisUtil.set(UMSConstants.REDIS_KEY_API_PERMISSION_PREFIX + umsApi.getApiUrl(), JSON.toJSONString(roleIds));
        } else {
            redisUtil.delete(UMSConstants.REDIS_KEY_API_PERMISSION_PREFIX + umsApi.getApiUrl());
        }
    }

    /**
     * 绑定接口关联的菜单
     *
     * @param umsApiDo 实体
     * @return
     */
    public Boolean bindApiRelationMenu(UmsApiDo umsApiDo) {
        if(StrUtil.isBlank(umsApiDo.getId())) {
            throw new BusinessException("接口ID不能为空");
        }
        if(StrUtil.isBlank(umsApiDo.getMenuId())) {
            throw new BusinessException("菜单ID不能为空");
        }
        UmsApi umsApi = new UmsApi();
        umsApi.setId(umsApiDo.getId());
        umsApi.setMenuId(umsApiDo.getMenuId());

        boolean result = umsApiService.updateById(umsApi);
        if (!result) {
            throw new BusinessException("绑定接口关联的菜单失败");
        }
        return true;
    }
}
